import React, { PureComponent } from 'react'
import {
  Spin, Tree, Input,
} from 'antd'
import { ResizableBox } from 'react-resizable'
import ReactDOM from 'react-dom'
import HufuTreeTitle from './treeNode'
import styles from './index.less'

const { DirectoryTree } = Tree
const { Search } = Input

// const dataList = []
// const generateList = data => {
//   for (let i = 0; i < data.length; i++) {
//     const node = data[i]
//     const { key, title } = node
//     dataList.push({ key, title })
//     if (node.children) {
//       generateList(node.children)
//     }
//   }
// }

// const getParentKey = (key, tree) => {
//   let parentKey
//   for (let i = 0; i < tree.length; i++) {
//     const node = tree[i]
//     if (node.children) {
//       if (node.children.some(item => item.key === key)) {
//         parentKey = node.key
//       } else if (getParentKey(key, node.children)) {
//         parentKey = getParentKey(key, node.children)
//       }
//     }
//   }
//   return parentKey
// }

/**
 * 虎符Tree组件
 * treeData         内容请通过treeData传入，在新版antd的tree组件中用children的方式传虽然依旧生效但控制台会报错警告
 *                  如果需要用搜索，请保证treeData中每个节点的title是string，如果想传入ReactNode请通过renderTreeNodes做后续修改
 * renderTreeNodes  如果想要修改treeNode内的渲染，可通过此参数传入方法，修改每个节点的title，title类型可以为ReactNode或String
 * searchValue      搜索框绑定的value值，放在props里传入是方便外部调用下方的rendSearchTitle方法渲染被搜索匹配到的节点
 * onSearchChange   搜索框的onchange事件的回调，需要在里面更新searchValue的值
 * showTitle        是否显示最上方的标题
 * title            最上方的标题显示的内容
 * selectedKeys     已选中节点的key
 * onSelect         tree节点选中事件
 * draggable        是否支持拖动
 * onExpand         拖拽进入某一个节点事件
 * onDrop           拖动结束事件
 * onExpand         文件夹展开事件
 */
export default class ProTree extends PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      expandedKeys: props.expandedKeys || [],
      width: props.width || 258,
      treeDataList: props.treeData,
    }

    this.instence = null
    // generateList(props.treeData)
  }

  componentDidMount() {
    this.box.oncontextmenu = (e) => false
  }

  /**
   * 当treeData改变时，触发,更新dataList，来确保搜索正确
   * @param {*} nextProps
   * @param {*} prevState
   */
  static getDerivedStateFromProps(nextProps, prevState) {
    const { treeData } = nextProps
    // 当传入的type发生变化的时候，更新state
    if (treeData !== prevState.treeDataList) {
      // generateList(treeData)
      return {
        treeDataList: treeData,
      }
    }
    // 否则，对于state不进行任何操作
    return null
  }

  /**
   * 文件夹展开事件
   * @param {string[]} keys
   */
  onExpand = (expandedKeys) => {
    this.setState({
      expandedKeys,
    })
    this.props.onExpand && this.props.onExpand(expandedKeys)
  }

  /**
   * tree节点选中事件
   * @param {string[]} selectedKeys 选中的节点
   * @param {Object} e {selected: bool, selectedNodes, node, event}
   */
  onSelect = (selectedKeys, e) => {
    this.props.onSelect && this.props.onSelect(selectedKeys, e)
  }

  /**
   * 拖拽进入某一个节点事件
   * @param {Object} opt
   */
  onDragEnter(opt) {
    this.props.onDragEnter && this.props.onDragEnter(opt)
    // 如果有展开过滤，那么先调用展开过滤器
    if (this.props.dragExpandFilter && this.props.dragExpandFilter(opt)) {
      return
    }

    this.props.onExpand && this.props.onExpand(opt.expandedKeys)
  }

  /**
   * 拖动结束事件
   * @param {Object} opt
   */
  onDrop(opt) {
    this.props.onDrop && this.props.onDrop(opt)
  }

  // onSearchChange = value => {
  //   const { treeData } = this.props
  //   const expandedKeys = dataList
  //     .map(item => {
  //       if (item.title.indexOf(value) > -1) {
  //         return getParentKey(item.key, treeData)
  //       }
  //       return null
  //     })
  //     .filter((item, i, self) => item && self.indexOf(item) === i)
  //   this.setState({
  //     expandedKeys,
  //   }, () => {
  //     this.props.onSearchChange && this.props.onSearchChange(value)
  //   })
  // }

  // 默认的icon方法，如果不传icon且不传renderTreeNodes方法，就会采用这套icon。
  // 如果某些情况不需要显示icon，icon传true即可
  getIcon = (name) => <i className={`iconfont-colour2 ${name}`} />

  defaultIconFun = (icon) => {
    const { selectedKeys } = this.props
    if (selectedKeys && selectedKeys[0] === icon.data.key) {
      return this.getIcon(icon.expanded ? 'icon-wenjianjia-dakaihover' : 'icon-wenjianjia-morenhover')
    }
    return this.getIcon(icon.expanded ? 'icon-wenjianjia-dakai' : 'icon-wenjianjia-moren')
  }

  render() {
    const {
      expandedKeys, width, treeDataList,
    } = this.state
    const {
      loading, draggable, showSearch, title, selectedKeys, showTitle, defaultExpandedKeys,
      switcherIcon, renderTreeNodes, height,
    } = this.props
    const loop = data => data.map(item => {
      const {
        title: titleStr, icon, children, ...restProps
      } = item
      const titleObj = titleStr
      const treeItem = {
        title: titleObj,
        icon: icon || this.defaultIconFun,
        ...restProps,
      }
      children && (treeItem.children = loop(children))
      return treeItem
    })
    const tempTreeData = renderTreeNodes ? renderTreeNodes(treeDataList) : loop(treeDataList)
    return (
      <div
        ref={(dev) => {
          this.box = dev
        }}
        className={styles.pro_tree_resize_box}
        {...(height ? { style: { height } } : {})}
      >
        <ResizableBox
          className={styles.pro_tree_resize}
          ref={(e) => {
            this.instence = e
          }}
          axis="y"
          width={width}
          height={Infinity}
          onResize={(e, direction) => {
            const dom = ReactDOM.findDOMNode(this.instence)
            let widths = 208
            if (dom) {
              widths = dom.getBoundingClientRect().left
            }
            if (e.clientX - widths > 208 && e.clientX - 208 < 800) {
              this.setState({ width: e.clientX - widths })
            }
          }}
        >
          <Spin spinning={loading || false}>
            <div className={styles.pro_tree}>
              {/*  顶部title  */}
              {(showTitle === undefined || showTitle === true) && (
                <div className={styles.pro_tree_name}>
                  <span className={styles.pro_tree_name_text}>{title || '目录'}</span>
                  <span className={styles.pro_tree_name_icons}>
                    {this.props.operations || null}
                  </span>
                </div>
              )}
              {/*  搜索框  */}
              {showSearch ? (
                <div className={styles.pro_tree_search}>
                  <Search
                    allowClear
                    placeholder={
                      this.props.searchPlaceholder || '请输入搜索名称'
                    }
                    onSearch={(value) => {
                      this.props.search && this.props.search(value)
                    }}
                  />
                </div>
              ) : (showTitle === undefined || showTitle === true && (
                <div style={{ height: '0.1rem' }} />
              ))}
              {/*  tree主体  */}
              <div className={styles.pro_tree_main}>
                <DirectoryTree
                  blockNode
                  draggable={draggable || false}
                  onDragEnter={this.onDragEnter.bind(this)}
                  onDrop={this.onDrop.bind(this)}
                  selectedKeys={selectedKeys || []}
                  onSelect={this.onSelect}
                  expandedKeys={expandedKeys || []}
                  onExpand={this.onExpand.bind(this)}
                  defaultExpandedKeys={defaultExpandedKeys}
                  switcherIcon={switcherIcon}
                  treeData={tempTreeData}
                />
              </div>
            </div>
          </Spin>
        </ResizableBox>
      </div>
    )
  }
}

// 调用这个方法可以把匹配搜索内容的部分标成红色，但请保证title是String
const renderSearchTitle = (title, searchValue) => {
  if (title && searchValue) {
    const index = title.indexOf(searchValue)
    const beforeStr = title.substr(0, index)
    const afterStr = title.substr(index + searchValue.length)
    return index > -1 ? (
      <span>
        {beforeStr}
        <span className={styles.site_tree_search_value}>{searchValue}</span>
        {afterStr}
      </span>
    ) : (
      <span>{title}</span>
    )
  }
  return title
}

/**
 * 搜索树形结构，如果匹配的结果有pid，那么需要一直查找到顶部
 * O(3n)
 * @param {*} value 搜索值
 * @param {*} keyStr 特征值
 * @param {*} listDatas 列表值
 */
const searchTreeListByName = (value, listDatas, keyStr = 'name') => {
  let result = []
  const fatchIds = [] // 要展开的父节点id
  const filtered = new Set() // 过滤的查找值结果id
  const recycleFlagIds = new Set()
  const hashMap = new Map()

  if (value && listDatas) {
    listDatas.forEach((item) => {
      hashMap.set(item.id, item)
      item.recycleFlag && recycleFlagIds.add(item.id)
    })
    listDatas.forEach((item) => {
      // 如果已经被查找到了，不用重复查找
      if (filtered.has(item.id)) {
        return
      }
      if (
        item[keyStr].toLowerCase().indexOf(value.toLowerCase()) !== -1
        || (item.keywords && item.keywords.join(',').toLowerCase().indexOf(value.toLowerCase()) !== -1)
      ) {
        let temp = item
        // 递归寻找pid直到结束
        while (temp && !filtered.has(temp.id) && hashMap.has(temp.id)) {
          filtered.add(temp.id)
          temp = hashMap.get(temp.pid)
        }
      }
    })

    result = listDatas.filter((item) => filtered.has(item.id))
    filtered.forEach((item) => {
      // 寻找要展开的父节点
      if (!recycleFlagIds.has(item)) {
        fatchIds.push(`${item}`)
      }
    })
  } else {
    result = listDatas
  }
  return { result, fatchIds }
}

export { HufuTreeTitle, renderSearchTitle, searchTreeListByName }
